//: Playground - noun: a place where people can play

import UIKit
//: # swfit 读书笔记

//: ## 泛型

//: ### 泛型所解决的问题
//: 就是 用 <T> 这个抽象的类型，来代替具体的类型 String Int 。。。
//: 也不一定一定是  <T> 代表泛型

//: ### 泛型函数
func swapTwoValues <QWE>(a:inout QWE,b:inout QWE){
    let temporaryA = a
    a = b
    b = temporaryA
}

var stringOne = "a"
var stringTwo = "b"
print("stringOne - \(stringOne),stringTwo - \(stringTwo)")
swap(&stringOne, &stringTwo)
print("stringOne - \(stringOne),stringTwo - \(stringTwo)")
//: ### 类型参数
//: 意思是说 T 的类型确定了就不能瞎改了
//: T 代表泛型
func palyPrint<QWE,ASD>(a:QWE , b:QWE, c:ASD, d:ASD){
    print("a - \(a),b - \(b),c - \(c),d - \(d)")
}
let a = 1
let b = 2
let c = "c"
let d = "d"

palyPrint(a: a, b: b, c: c, d: d)

//: ### 命名类型参数
//: 泛型和函数有关联时 需要写 英文 并且是驼峰命名方式
//: 没啥关系就用大写字母代替

//: ### 泛型类型
//: 自己模拟实现 入栈和出栈
struct Stack<Element>{
    var items = [Element]()
    
    mutating func push(pushVC:Element) {
        items.append(pushVC)
    }
    
    mutating func pop(){
        items.removeLast()
    }
    
}

//: ### 扩展一个泛型类型
//: 不知道说啥， 就是给泛型扩展方法而已
extension Stack{
    var topItem:Element{
        return (items.isEmpty ? nil:items.last)!
    }
}

//: ### 类型约束
//: 先科普点知识  Swift 标准库中定义了一个 Equatable 协议，该协议要求任何遵循该协议的类型必须实现等式符（==）及不等符(!=)，从而能对该类型的任意两个值进行比较。所有的 Swift 标准类型自动支持 Equatable 协议。
//: 泛型的约束就是 在 T 后面加上： 让他遵守某个协议或者继承某个类

func weAreTwins (bodyOne:String,bodyTwo:String) -> Bool{
    if bodyOne == bodyTwo{
        return true
    }else{
        return false
    }
}

func weAreTwinGenericity<T:Equatable> (bodyOne:T,bodyTwo:T) -> Bool{
    if bodyOne == bodyTwo{
        return true
    }else{
        return false
    }
}

func sameAge <T:Equatable>(ageOne:T,ageTwo:T) -> Bool{
    return true
}
//: ### 关联类型
//: 就是协议泛型
protocol Container{
    associatedtype itemType
    mutating func addItem(item:itemType)
    var itemsCount:Int{get}
    subscript(i:Int)->itemType{get}
}


struct associatedtypeStruct<T>:Container{
    var items = [T]() 
    
    mutating func addItem(item: T) {
        self.items.append(item)
    }
    
    var itemsCount: Int{
        return items.count
    }
    
    subscript(i:Int)->T{
        return items[i]
    }
    
}


//: ### 泛型 where 语句

func allItemMatch<c1:Container,c2:Container>(itemOne:c1,itemTwo:c2) -> Bool where c1.itemType == c2.itemType,c1.itemType:Equatable{
    
    if itemOne.itemsCount != itemTwo.itemsCount{
        return false
    }
    
    return true
}

